package com.redijedi.tapestry.components;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.apache.tapestry.ComponentResources;
import org.apache.tapestry.Field;
import org.apache.tapestry.MarkupWriter;
import org.apache.tapestry.OptionModel;
import org.apache.tapestry.SelectModel;
import org.apache.tapestry.annotations.AfterRenderTemplate;
import org.apache.tapestry.annotations.BeforeRenderTemplate;
import org.apache.tapestry.annotations.Component;
import org.apache.tapestry.annotations.Inject;
import org.apache.tapestry.annotations.Parameter;
import org.apache.tapestry.corelib.components.Select;
import org.apache.tapestry.internal.OptionModelImpl;
import org.apache.tapestry.internal.SelectModelImpl;

/**
 * @author torr
 * 
 */
public class DropDownDateField implements Field {

	@Inject
	private ComponentResources _resources;

	@Parameter(value = "prop:componentResources.id", defaultPrefix = "literal")
	private String _id;

	@Parameter(value = "prop:componentResources.elementName", defaultPrefix = "literal")
	private String _elementName;

	@Parameter(defaultPrefix = "literal")
	private String _label;

	@Parameter(value = "month, day, year", defaultPrefix = "literal")
	private String _order;

	@Parameter(value = "2000", defaultPrefix = "literal")
	private String _fromYear;

	@Parameter(value = "2010", defaultPrefix = "literal")
	private String _toYear;

	@Parameter(value = "false", defaultPrefix = "literal")
	private boolean _disabled;

	@Parameter(required = true)
	private Object _value;

	@SuppressWarnings("unused")
	@Component(parameters = { "model=yearSelectModel", "value=yearSelected" })
	private Select _yearSelect;

	@SuppressWarnings("unused")
	@Component(parameters = { "model=monthSelectModel", "value=monthSelected" })
	private Select _monthSelect;

	@SuppressWarnings("unused")
	@Component(parameters = { "model=daySelectModel", "value=daySelected" })
	private Select _daySelect;

	private String yearSelected;

	private String monthSelected;

	private String daySelected;

	private enum Months {
		JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC
	}

	/**
	 * @return the _value
	 */
	public Object getValue() {
		return _value;
	}

	/**
	 * @param _value
	 *            the _value to set
	 */
	public void setValue(Object value) {
		_value = convertStringToDate(monthSelected + "/" + daySelected + "/"
				+ yearSelected);
	}

	/**
	 * @return the yearSelected
	 */
	public String getYearSelected() {
		return yearSelected;
	}

	/**
	 * @param yearSelected
	 *            the yearSelected to set
	 */
	public void setYearSelected(String yearSelected) {
		this.yearSelected = yearSelected;
	}

	/**
	 * @return the monthSelected
	 */
	public String getMonthSelected() {
		return monthSelected;
	}

	/**
	 * @param monthSelected
	 *            the monthSelected to set
	 */
	public void setMonthSelected(String monthSelected) {
		this.monthSelected = monthSelected;
	}

	/**
	 * @return the daySelected
	 */
	public String getDaySelected() {
		return daySelected;
	}

	/**
	 * @param daySelected
	 *            the daySelected to set
	 */
	public void setDaySelected(String daySelected) {
		this.daySelected = daySelected;
	}

	public List<String> getYears() {
		int from = Integer.parseInt(_fromYear);
		int to = Integer.parseInt(_toYear);
		List<String> years = new ArrayList<String>();
		for (int i = from; i <= to; i++) {
			years.add(String.valueOf(i));
		}
		return years;
	}

	public List<String> getMonths() {
		List<String> months = new ArrayList<String>();
		for (Months m : Months.values()) {
			months.add(m.name());
		}
		return months;
	}

	public List<String> getDays() {
		List<String> days = new ArrayList<String>();
		for (int i = 0; i < 31;) {
			days.add(String.valueOf(++i));
		}
		return days;
	}

	public SelectModel getYearSelectModel() {
		if (getYears().size() == 0) {
			return null;
		}
		List<OptionModel> options = new ArrayList<OptionModel>();
		for (String y : getYears()) {
			OptionModel option = new OptionModelImpl(y, isDisabled(), y);
			options.add(option);
		}
		return new SelectModelImpl(null, options);
	}

	public SelectModel getMonthSelectModel() {
		if (getMonths().size() == 0) {
			return null;
		}
		List<OptionModel> options = new ArrayList<OptionModel>();
		int i = 0;
		for (String y : getMonths()) {
			OptionModel option = new OptionModelImpl(y, isDisabled(), String
					.valueOf(++i));
			options.add(option);
		}
		return new SelectModelImpl(null, options);
	}

	public SelectModel getDaySelectModel() {
		if (getDays().size() == 0) {
			return null;
		}
		List<OptionModel> options = new ArrayList<OptionModel>();
		int i = 0;
		for (String y : getDays()) {
			OptionModel option = new OptionModelImpl(y, isDisabled(), String
					.valueOf(++i));
			options.add(option);
		}
		return new SelectModelImpl(null, options);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.apache.tapestry.ClientElement#getClientId()
	 */
	public String getClientId() {
		return _id;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.apache.tapestry.Field#getElementName()
	 */
	public String getElementName() {
		return _elementName;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.apache.tapestry.Field#getLabel()
	 */
	public String getLabel() {
		return _label;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.apache.tapestry.Field#isDisabled()
	 */
	public boolean isDisabled() {
		return _disabled;
	}

	public String getYearValue() {
		Date d = getConvertedValue();
		Calendar c = Calendar.getInstance();
		c.setTime(d);
		if (d != null) {
			return String.valueOf(c.get(Calendar.YEAR));
		}
		return null;
	}

	public String getMonthValue() {
		Date d = getConvertedValue();
		Calendar c = Calendar.getInstance();
		c.setTime(d);
		if (d != null) {
			return String.valueOf(c.get(Calendar.MONTH));
		}
		return null;
	}

	public String getDayValue() {
		Date d = getConvertedValue();
		Calendar c = Calendar.getInstance();
		c.setTime(d);
		if (d != null) {
			return String.valueOf(c.get(Calendar.DATE));
		}
		return null;
	}

	public String getOrder() {
		return _order.replace(" ", "").toLowerCase();
	}

	private Date getConvertedValue() {
		if (_value instanceof String) {
			return convertStringToDate((String) _value);
		} else if (_value instanceof Date) {
			return (Date) _value;
		} else if (_value instanceof java.sql.Date) {
			return (Date) ((java.sql.Date) _value);
		}
		return null;
	}

	private Date convertStringToDate(String stringDate) {
		DateFormat format = new SimpleDateFormat();
		Date date = null;
		try {
			date = format.parse(stringDate);
		} catch (Exception e) {

		}
		return date;
	}

	private Date convertObjectToDate(Object object) {
		if (object instanceof String) {
			return convertStringToDate((String) object);
		} else if (object instanceof Date) {
			return (Date) object;
		} else if (object instanceof java.sql.Date) {
			return (Date) ((java.sql.Date) object);
		}
		return null;
	}

	@BeforeRenderTemplate
	void renderBeginTag(MarkupWriter writer) {
		if (_elementName != null) {
			writer.element(_elementName);
			writer.attributes("id", getClientId());
			_resources.renderInformalParameters(writer);
		}
	}

	@AfterRenderTemplate
	void renderEndTag(MarkupWriter writer) {
		if (_elementName != null) {
			writer.end();
		}
	}

}
